package com.frx.fakeroutexposed.services;


import android.app.Notification;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationManager;
import android.os.Build;
import android.os.IBinder;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;

import com.frx.fakeroutexposed.R;
import com.frx.fakeroutexposed.events.ConfigEvent;
import com.frx.fakeroutexposed.events.GpsInfoEvent;
import com.frx.fakeroutexposed.events.MockFlagEvent;
import com.frx.fakeroutexposed.tools.MY_NAMES;
import com.frx.fakeroutexposed.tools.SettingsHelper;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;


public class BackgroundsServices extends Service {
    /**
     * 是否开启模拟的标志位,默认为 false<br>
     * true,开启<br>
     * false,关闭
     */
    //private boolean mFlagHook = false;

    private Notification myNotify;
    /**
     * 参数配置,也用于存入GPS数据
     */
    private SettingsHelper mSettings;
    private Timer timer;
    private TimerTask timeTask;
    /**
     * 模拟位置提供者,这里使用的是GPS_PROVIDER
     */
    private String mMOC_LOCATION_PROVIDER = LocationManager.GPS_PROVIDER;
    /**
     * 位置管理器
     */
    private LocationManager lm;

    /**
     * 保存GPS坐标点的List
     */
    ArrayList<String> mGpsDataList = new ArrayList<>();

    @Override
    public IBinder onBind(Intent intent) {

        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        //===================================
        lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        //绑定监听，有4个参数
        //参数1，设备：有GPS_PROVIDER和NETWORK_PROVIDER两种
        //参数2，位置信息更新周期，单位毫秒
        //参数3，位置变化最小距离：当位置距离变化超过此值时，将更新位置信息
        //参数4，监听
        //备注：参数2和3，如果参数3不为0，则以参数3为准；参数3为0，则通过时间来定时更新；两者为0，则随时刷新
        // 2秒更新一次，或最小位移变化超过1米更新一次；
        //注意：此处更新准确度非常低，推荐在service里面启动一个Thread，在run中sleep(10000);然后执行handler.sendMessage(),更新位置

        lm.addTestProvider(mMOC_LOCATION_PROVIDER, false, false,
                false, false, true, true, true, 0, 5);
        lm.setTestProviderEnabled(mMOC_LOCATION_PROVIDER, true);
        //===================================
        //注意mSettings一定不能在定义变量时初始化,因为this所代表的上下文,此时还没有初始化.
        mSettings = new SettingsHelper(this);


        //============================
        Log.d("debug", "service启动");
        //EventBus,注册为订阅者
        EventBus.getDefault().register(this);
        // 构造一个notification
        myNotify = new Notification.Builder(this)
                .setSmallIcon(R.drawable.ic_launcher)
                .setContentTitle(getText(R.string.notification_content_title))
                .setContentText(getText(R.string.notification_content_text))
                .getNotification();
        /*
		 * Notification.FLAG_NO_CLEAR; // 点击清除按钮时就会清除消息通知,但是点击通知栏的通知时不会消失
		 * Notification.FLAG_ONGOING_EVENT; // 点击清除按钮不会清除消息通知,可以用来表示在正在运行
		 * Notification.FLAG_AUTO_CANCEL; // 点击清除按钮或点击通知后会自动消失
		 * Notification.FLAG_INSISTENT; // 一直进行，比如音乐一直播放，直到用户响应
		 */
        // 点击清除按钮不会清除消息通知,可以用来表示在正在运行
        myNotify.flags = Notification.FLAG_ONGOING_EVENT;
        // mNotificationManager.notify(1564789, myNotify);
        // startForeground(1, myNotify);
        //this.setHookFlag(false);
    }

    //==================================

    /**
     * 设置模拟标志位,默认为 false<br>
     * true,开启<br>
     * false,关闭
    private void setHookFlag(boolean flag) {
        this.mFlagHook = flag;
    }*/
    //==================================

    //

    /**
     * 通过系统的"模拟位置"功能,模拟 GPS 坐标信息
     *
     * @param event 包含GPS信息的 Event
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEventMockLocation(GpsInfoEvent event) {
        //将索引存储在 SharedPreferences
        //这是为了在中断后,可以继续从中断点开始模拟
        //TODO 添加暂停,恢复模拟
        mSettings.setInt(MY_NAMES.KEY_INDEX, event.getIndex());
        Location location = new Location(mMOC_LOCATION_PROVIDER);
        // 分别设置经度,纬度,海拔
        Double longitude = event.getLongitude();
        Double latitude = event.getLatitude();
        Double altitude = event.getAltitude();

        location.setLatitude(latitude);
        location.setLongitude(longitude);
        location.setAltitude(altitude);
        location.setAccuracy(3);
        location.setTime(System.currentTimeMillis());

		/*
		 * 在android4.2之后的版本里对Location这个类做个细微的改动，
		 * 增加了setElapsedRealtimeNanos和getElapsedRealtimeNanos两个方法。
		 * 报错"Incomplete location object, missing timestamp or accuracy"
		 * 就是没有为location的实例设置ElapsedRealtimeNanos
		 */
        if (Build.VERSION.SDK_INT >= 17) {
            location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
        }

        Log.d("fakeGps", "SET GPS ----------" + latitude + "---" + longitude);
        lm.setTestProviderLocation(mMOC_LOCATION_PROVIDER, location);
    }
    //====================================

    /**
     * 开启/关闭"模拟位置"的Timer
     *
     * @param event 用于处理hook信息的Event
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEventStartTimerForMock(MockFlagEvent event) {

        // 改变按钮状态的Event
        ConfigEvent changeBtnEvent = new ConfigEvent();
        if (event.isStartHook()) {
            // 将service设置为前台
            startForeground(1, myNotify);
            //==========================================
            //生成需要模拟的 GPS 坐标数据
            if(event.isFlag_mock_single_loc()){//模拟固定坐标
                String info = event.getLongitude()+MY_NAMES.SPLIT_STRING_COMMA
                        +event.getLatitude()+MY_NAMES.SPLIT_STRING_COMMA
                        +event.getAltitude();
                mGpsDataList.add(info);
            }else{
                String fileName = mSettings.getString(
                        MY_NAMES.KEY_FILE_GPS_DATA, "");
                if(!fileName.equals("")){//如果文件名不为空,则从文件中读取数据
                    mGpsDataList = loadGPSDataFromFile(fileName);
                }
            }
            //==========================================
            //从 SharedPreferences 中取出索引,再从 adapter 中取出时间间隔(单位S),再转换为MS
            String[] time_intervalStrings = getResources().getStringArray(R.array.time_interval);
            Integer time_interval=
                    1000*Integer.valueOf(
                    time_intervalStrings[mSettings.getInt(MY_NAMES.KEY_FAKE_TIME_INTERVAL_INDEX,0)]);
            //==========================================
            //将开启模拟的标志位设置为true
            //this.setHookFlag(true);
            try {

                // 每次都需要重新 new Timer TimerTask,否则会有 IllegalStateException 异常
                timer = new Timer();
                timeTask = new MyTimerTask();
                timer.schedule(timeTask, 0, time_interval);
            } catch (IllegalStateException e) {
                Log.i("timer:", "timer异常");
                e.printStackTrace();
            }
            //改变按钮状态
            changeBtnEvent.setFlag_start_fake(true);
            //接收者在 MapViewFragments 类的 onEventChangeButtonStatues()
            EventBus.getDefault().post(changeBtnEvent);

        } else {
            // 将SharedPreferences中GPS信息重置
            clearSettings();
            if (timeTask != null) {
                // 如果不 cancel 会报错
                timeTask.cancel();
            }
            if (timer != null) {
                timer.cancel();
                timer.purge();
                timer = null;
            }

            stopForeground(true);
            //改变按钮状态
            changeBtnEvent.setFlag_start_fake(false);
            //接收者在 MapViewFragments 类的 onEventChangeButtonStatues()
            EventBus.getDefault().post(changeBtnEvent);

        }
    }
    //==================================

    /**
     * 模拟轨迹前的一些配置信息的处理
     *
     * @param event 包含配置信息的 Event
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEventConfig2SharedPreferences(ConfigEvent event) {
        // 将GPS数据所在的文件的名字保存到SharedPreferences
        String fileName = event.getGpsDataFileNameFullPath();
        if (!((null == fileName) || "".equals(fileName))) {
            // 将含有GPS数据的文件的完整路径保存在SharedPreferences
            mSettings.setString(MY_NAMES.KEY_FILE_GPS_DATA, fileName);
        }
    }
    //==================================

    /**
     * 重置SharedPreferences中的配置信息.
     */
    private void clearSettings() {
       // this.setHookFlag(false);
        //清除 List 中的数据
        mGpsDataList.clear();
        //将SharedPreferences中的索引重置0
        mSettings.setInt(MY_NAMES.KEY_INDEX, 0);
        //将存储GPS数据的文件的名字重置为空
        mSettings.setString(MY_NAMES.KEY_FILE_GPS_DATA, "");

    }
    //==================================

    /**
     * 判断GPS是否开启
     *
     * @return true 表示开启
     */
    public boolean isOPen() {
        // 通过 WLAN 或移动网络(3G/2G)确定的位置
        // （也称作A-GPS，辅助GPS定位。主要用于在室内或遮盖物（建筑群或茂密的深林等）密集的地方定位）
        //boolean network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        return lm.isProviderEnabled(LocationManager.GPS_PROVIDER);

    }

    //---------------------------

    /**
     * 获取 Location 用于判断是否定位成功
     *
     * @return Location
     */
    public Location getLocation() {
        //lm.getLastKnownLocation(LocationManager.GPS_PROVIDER)
        return null;
    }

    //==================================
    class MyTimerTask extends TimerTask {

        @Override
        public void run() {

            //开始模拟

            // ===============================================
            // 从 ArrayList 中读取GPS数据
            // 从SharedPreferences中读取索引
            int index = mSettings.getInt(MY_NAMES.KEY_INDEX, 0);
            // 如果不停止模拟,模拟结束后,将保持在最后位置,也用于模拟单个固定坐标
            if (index >= mGpsDataList.size()) {
                index = mGpsDataList.size()-1;
            }
            String str = mGpsDataList.get(index);
            Log.d("(Timer)模拟的经纬度:", str);
            if (TextUtils.isEmpty(str)) {
                return;
            }
            // 将逗号分隔的数据变成数组
            String[] parts = str.split(MY_NAMES.SPLIT_STRING_COMMA);
            Double longitude = 0.0;
            Double latitude = 0.0;
            Double altitude = 0.0;
            if (parts.length >= 3) {// 防止数据不够,数组下标越界
                longitude = Double.valueOf(parts[0]);
                latitude = Double.valueOf(parts[1]);
                altitude = Double.valueOf(parts[2]);
            }
            //读取数据完成
            //===============================================
            //移动到下一个点
            index++;
            //===============================================
            //EventBus post event
            //该 Event 的接收者就是本类的方法：
            // onEventMockLocation(GpsInfoEvent event)
            GpsInfoEvent gpsEvent = new GpsInfoEvent();
            gpsEvent.setLongitude(longitude);
            gpsEvent.setLatitude(latitude);
            gpsEvent.setAltitude(altitude);
            gpsEvent.setIndex(index);
            EventBus.getDefault().post(gpsEvent);
            //post完成
            //===============================================
        }
    }

    //==================================

    /**
     * 从文件读取GPS信息
     *
     * @param fileName 文件的完整路径
     * @return ArrayList<String> 包含 GPS 信息的 List
     */
    private ArrayList<String> loadGPSDataFromFile(String fileName) {
        //保存GPS坐标点的List
        ArrayList<String> mGpsDataList = new ArrayList<>();
        //InputStream is;
        try {//从文件中读取数据
                            /*is = openFileInput(mSettings.getString(MY_NAMES.KEY_FILE_GPS_DATA, ""));
							// 不能用FileReader初始化BufferedReader,会报错:找不到文件.原因未知,暂且不理.
							BufferedReader reader = new BufferedReader(
									new InputStreamReader(is));
							while (reader.ready()) {
								mGpsDataList.add(reader.readLine());
							}*/
            //=========================================
            File file = new File(fileName);
            if (file.exists()) {
                InputStream instream = new FileInputStream(file);
                InputStreamReader inputreader = new InputStreamReader(
                        instream);
                BufferedReader buffreader = new BufferedReader(
                        inputreader);
                String line;
                // 分行读取
                while (buffreader.ready()) {
                    if ((line = buffreader.readLine()) != null) {
                        mGpsDataList.add(line);
                    }
                }
                instream.close();
            }
            //=========================================
            //重置索引
            //mSettings.setInt(MY_NAMES.KEY_INDEX, 0);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return mGpsDataList;
    }

    //=============================================
    /*class MyTimerTask_old extends TimerTask {
        *//***
         * 定时将GPS坐标信息,通过 EventBus 发送
         *//*

        //保存GPS坐标点的List
        ArrayList<String> mGpsDataList = new ArrayList<>();

        @Override
        public void run() {
            if (mFlagHook) {
                //开始模拟
                if (0 == mGpsDataList.size()) {//mGpsDataList中没有数据的时候才从文件读取
                    //InputStream is;
                    try {//从文件中读取数据
							*//*is = openFileInput(mSettings.getString(MY_NAMES.KEY_FILE_GPS_DATA, ""));
							// 不能用FileReader初始化BufferedReader,会报错:找不到文件.原因未知,暂且不理.
							BufferedReader reader = new BufferedReader(
									new InputStreamReader(is));
							while (reader.ready()) {
								mGpsDataList.add(reader.readLine());
							}*//*
                        //=========================================
                        File file = new File(mSettings.getString(
                                MY_NAMES.KEY_FILE_GPS_DATA, ""));
                        if (file.exists()) {
                            InputStream instream = new FileInputStream(file);
                            InputStreamReader inputreader = new InputStreamReader(
                                    instream);
                            BufferedReader buffreader = new BufferedReader(
                                    inputreader);
                            String line;
                            // 分行读取
                            while (buffreader.ready()) {
                                if ((line = buffreader.readLine()) != null) {
                                    mGpsDataList.add(line);
                                }
                            }
                            instream.close();
                        }
                        //=========================================
                        //重置索引
                        mSettings.setInt(MY_NAMES.KEY_INDEX, 0);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                } else {
                    // ===============================================
                    // 从 ArrayList 中读取GPS数据
                    // 从SharedPreferences中读取索引
                    int index = mSettings.getInt(MY_NAMES.KEY_INDEX, 0);
                    // 如果不停止模拟,模拟结束后,将保持在最后位置
                    if (index >= mGpsDataList.size()) {
                        index = mGpsDataList.size();
                    }
                    String str = mGpsDataList.get(index);
                    Log.d("(Timer)模拟的经纬度:", str);
                    if (TextUtils.isEmpty(str)) {
                        return;
                    }
                    // 将逗号分隔的数据变成数组
                    String[] parts = str.split(MY_NAMES.SPLIT_STRING_COMMA);
                    Double longitude = 0.0;
                    Double latitude = 0.0;
                    Double altitude = 0.0;
                    if (parts.length >= 3) {// 防止数据不够,数组下标越界
                        longitude = Double.valueOf(parts[0]);
                        latitude = Double.valueOf(parts[1]);
                        altitude = Double.valueOf(parts[2]);
                    }
                    //读取数据完成
                    //===============================================
                    //移动到下一个点
                    index++;
                    //===============================================
                    //EventBus post event
                    //该 Event 的接收者就是本类的方法：
                    // onEventMockLocation(GpsInfoEvent event)
                    GpsInfoEvent gpsEvent = new GpsInfoEvent();
                    gpsEvent.setLongitude(longitude);
                    gpsEvent.setLatitude(latitude);
                    gpsEvent.setAltitude(altitude);
                    gpsEvent.setIndex(index);
                    EventBus.getDefault().post(gpsEvent);
                    //post完成
                    //===============================================
                }
            } else {//停止模拟的时候,清空List
                mGpsDataList.clear();
            }
        }

    }*/
    //
    //=============== end TimerTask =====================

    @Override
    public void onDestroy() {

        Log.d("service", "service onDestroy()");

        //禁止模拟
        lm.setTestProviderEnabled(mMOC_LOCATION_PROVIDER, true);
        // 将SharedPreferences中GPS信息重置
        clearSettings();
        //解除注册
        EventBus.getDefault().unregister(this);
        super.onDestroy();
    }


}
